#include "AssetReader.h"

namespace XpsAssets
{

	AssetReader::AssetReader(void)
	{
	}

	AssetReader::~AssetReader(void)
	{
	}


	void AssetReader::read(QString filename)
	{
		// Read XML
		QFile file(filename);

		if (!file.open(QFile::ReadOnly | QFile::Text))
			qDebug() << "error";

		xmlin.setDevice(&file);
		while (!xmlin.atEnd())
		{
			xmlin.readNext();

			if (xmlin.isStartElement())
			{
				if (xmlin.name() == "xps" && xmlin.attributes().value("version") == "1.0")
				{
					qDebug() << "starting to read xml file";
					readXML();
				}
				else
					qDebug() << "error: ";
			}
		}
		file.close();

		qDebug() << "Results: " << results.count();
		qDebug() << "Questions: " << questions.count();
		qDebug() << "Attributes: " << attributes.count();
	}

	void AssetReader::readXML()
	{
		//items.clear();

		Q_ASSERT(xmlin.isStartElement() && xmlin.name() == "xps");

		while (!xmlin.atEnd())
		{
			xmlin.readNext();
			if (xmlin.isEndElement())											break;
			if (xmlin.isStartElement() && xmlin.name() == "assets")	readAssets();
		}
	}

	void AssetReader::readAssets()
	{
		while (!xmlin.atEnd())
		{
			xmlin.readNext();

			if (xmlin.isStartElement())
			{
				if (xmlin.name() == "attributes")	readAttributesPool();
				if (xmlin.name() == "questions")	readQuestionsPool();
				if (xmlin.name() == "results")		readResults();
				if (xmlin.name() == "tree")			readTreeNodes();
			}
		}
	}
	void AssetReader::readAttributesPool()
	{
		while (!xmlin.atEnd())
		{
			xmlin.readNext();

			if (xmlin.isEndElement() && xmlin.name() == "attributes")
				break;

			if (xmlin.isStartElement() && xmlin.name() == "attribute")
			{
				int id = xmlin.attributes().value("id").toString().toInt();
				QString name = xmlin.attributes().value("name").toString();
				QString desc = xmlin.attributes().value("description").toString();
				int weight = xmlin.attributes().value("weight").toString().toInt();
				
				Attribute* a = attributes.create(id);
				a->setName(name);
				a->setDesc(desc);
				a->setWeight(weight);
			}

		}
	 
	}

	void AssetReader::readQuestionsPool()
	{
		XpsAssets::Question* cq = 0;

		while (!xmlin.atEnd())
		{
			xmlin.readNext();
			
			// questions pool end
			if (xmlin.isEndElement() && xmlin.name() == "questions")
				break;
			
			// current question end
			if (xmlin.isEndElement() && xmlin.name() == "question")
			{	
				cq = 0;
				continue;
			}
			
			// no relevant element
			if (!xmlin.isStartElement())
				continue;

			if (xmlin.name() == "question")
			{
				int id = xmlin.attributes().value("id").toString().toInt();
				QString text = xmlin.attributes().value("text").toString();
				cq = questions.create(id);
				cq->setText(text);
				cq->setChoiceMode(xmlin.attributes().value("mode").toString().toInt());
			}
			
			// add response to current question
			if (xmlin.name() == "response" && cq != 0)
			{
				Response* r = responses.create();
				cq->responses()->append(r->id());
				r->setParent(cq->id());
				r->setText(xmlin.attributes().value("text").toString());
			}

			// add attribute to last new response
			if (xmlin.name() == "attribute" && cq != 0)
			{
				int aid = xmlin.attributes().value("id").toString().toInt();
				int val = xmlin.attributes().value("value").toString().toInt();
				
				XpsAssets::Response* r = responses.get(cq->responses()->last());
				if (r->attributes()->contains(aid))
					continue;

				ResponseAttribute* ra = new ResponseAttribute();
				ra->setValue(val);
				r->attributes()->insert(aid, ra);
			}
		}
	}


	void AssetReader::readTreeNodes()
	{
		int x = 0, y = 0, id = 0;
		linkQueue.clear();
		QList<unsigned int> usedIDs;

		while (!xmlin.atEnd())
		{
			xmlin.readNext();
			
			if (xmlin.isEndElement() && xmlin.name() == "tree")
				break;

			if (!xmlin.isStartElement())
				continue;

			// read universal attributes 
			x = xmlin.attributes().value("x").toString().toInt();
			y = xmlin.attributes().value("y").toString().toInt();
			id = xmlin.attributes().value("id").toString().toInt();
			
			// abbrechen id bereits belegt: fehlerhafte id
			if (usedIDs.count() > 0 && usedIDs.contains(id) && xmlin.name() != "attribute" && xmlin.name() != "link")
			{
				QMessageBox::critical(0, "ID used", QString("Error while opening, problems with ids. id: %1").arg(id));
				qDebug() << "Error:\t" << xmlin.name().toString() << " - double use of id: " << id;
				return;
			}
			else if (xmlin.name() != "attribute" && xmlin.name() != "link")
			{
				qDebug() << "Id added: " << id << " type=" << xmlin.name();
				usedIDs.append(id);
			}

			// create nodes
			if (xmlin.name() == "start")		readNode(id, x, y, TreeNode::START);
			if (xmlin.name() == "end")			readNode(id, x, y, TreeNode::END);
			if (xmlin.name() == "question")		readQuestionNode(id, x, y);
			if (xmlin.name() == "constraint")	readConstraintNode(id, x, y);

			// collect links
			if (xmlin.name() == "link")
			{
				linkQueue.append(xmlin.attributes().value("parent").toString().toInt());
				linkQueue.append(xmlin.attributes().value("child").toString().toInt());

				if (xmlin.attributes().value("case").toString() == "true")
					linkQueue.append(1);
				else if (xmlin.attributes().value("case").toString() == "false")
					linkQueue.append(2);
				else
					linkQueue.append(0);
			}
		}

		qDebug() << "### LOAD # items in view: " << items.count();//diagram->graphicsView->scene()->items().count();
	}

	void AssetReader::readNode(int id, int x, int y, TreeNode::NodeType type)
	{
		QPoint position(x,y);
		TreeNode* item = new TreeNode(id, 
			type, 
			position);
		
		items.insert(id, item);
	}

	void AssetReader::readQuestionNode(int id, int x, int y)
	{
		QPoint position(x,y);
		TreeNode* item = new TreeNode(id, 
			TreeNode::QUESTION, 
			position, 
			xmlin.attributes().value("qid").toString().toInt());
		
		items.insert(id, item);
	}


	void AssetReader::readConstraintNode(int id, int x, int y)
	{
		int aid = -1;
		int compareMode = -1;
		int value = -1;
		ConstraintAttribute* ca = NULL;
		ConstraintNode* item = NULL;
		
		QPoint position(x,y);
		item = new ConstraintNode(id, position);
		items.insert(id, item);

		while (!xmlin.atEnd())
		{
			xmlin.readNext();

			if (xmlin.isEndElement() && xmlin.name() == "constraint")
				break;

			if (xmlin.isStartElement() && xmlin.name() == "attribute")
			{
				ca = new ConstraintAttribute();
				
				aid = xmlin.attributes().value("id").toString().toInt();
				compareMode = xmlin.attributes().value("compareMode").toString().toInt();
				value = xmlin.attributes().value("value").toString().toInt();
				
				ca->setValue(value);
				ca->setCompareMode((CompareMode) compareMode);
				item->attributes.insert(aid, ca);
			}
		}
	}


	void AssetReader::readResults()
	{
		int id = -1;

		while (!xmlin.atEnd())
		{
			xmlin.readNext();

			if (xmlin.isEndElement() && xmlin.name() == "results")
				break;

			if (xmlin.isStartElement() && xmlin.name() == "result")
			{
				id = xmlin.attributes().value("id").toString().toInt();
				QString name = xmlin.attributes().value("name").toString();
				QString desc = xmlin.attributes().value("description").toString();
				QString media = xmlin.attributes().value("mediapath").toString();

				Result* r = results.create(id);
				r->setName(name);
				// dem ergebnis alle bereits angelegten attribute zuweisen
				for (int i = 0; i < attributes.count(); i++)
				{
					ResultAttribute* newrsltattr = new ResultAttribute();
					results.get(id)->attributes()->insert(attributes.at(i)->id(), newrsltattr);
				}
			}

			if (xmlin.isStartElement() && xmlin.name() == "attribute")
			{
				int aid = xmlin.attributes().value("id").toString().toInt();
				int matchmode =  xmlin.attributes().value("matchmode").toString().toInt();
				int value =  xmlin.attributes().value("value").toString().toInt();
				int tolerance =  xmlin.attributes().value("tolerance").toString().toInt();

				if (id != -1)
				{
					results.get(id)->attribute(aid)->setMatchMode(matchmode);
					results.get(id)->attribute(aid)->setValue(value);
					results.get(id)->attribute(aid)->setTolerance(tolerance);
				}	
			}

		}
	 
	}


}